useLayoutEffect is a React Hook that fires synchronously after all DOM mutations but before the browser paints the screen, while useEffect fires asynchronously after the paint. This difference makes useLayoutEffect crucial for DOM measurements and preventing visual flicker, but useEffect is the default for most side effects due to better performance.
The core difference between useLayoutEffect and useEffect is the timing of their execution. useEffect runs asynchronously after the browser has finished painting the screen, meaning the user might see a brief flash of the initial state before the effect applies changes. useLayoutEffect, however, runs synchronously immediately after React has calculated all DOM mutations but before the browser paints, allowing you to make changes that are visible in the very first frame.
To visualize the order: when a component renders, React first updates the DOM, then useLayoutEffect fires, then the browser paints, and finally useEffect fires. This means useLayoutEffect blocks the browser's paint until it completes, which is why heavy computations in it can hurt performance, while useEffect lets the browser render immediately and does its work afterward.
Measuring DOM elements: When you need to get an element's dimensions (getBoundingClientRect(), offsetWidth) for calculations that affect the initial layout.
Preventing visual flicker: When making DOM changes that would be visible if they occurred after paint (e.g., adjusting scroll position, setting focus).
Synchronizing animations: When you need to read or write layout properties in the same frame to prevent layout thrashing.
Auto-resizing textareas: Calculating and applying new heights based on content before the user sees any height jump.
Data fetching: API calls, loading data from servers
Setting up subscriptions: Event listeners, WebSocket connections
Updating non-visual state: Document title, localStorage, analytics
Logging and analytics: Tracking page views or user interactions
Any side effect that doesn't need to block the user's view
Because useLayoutEffect is synchronous and blocks the browser's paint, it can degrade performance if used unnecessarily or if it contains expensive computations. The rule of thumb is: default to useEffect and only use useLayoutEffect when you need to read or write DOM layout before the user sees the screen. Overusing useLayoutEffect can lead to layout thrashing, where the browser is forced to repeatedly recalculate styles and layout, causing jank and poor frame rates.
useLayoutEffect does not run on the server during SSR because it requires the DOM to be present. If you're using Next.js or any SSR setup, React will log a warning when useLayoutEffect is used on the server. For code that runs in both environments, you can either use useEffect (which is safe for SSR) or conditionally import useLayoutEffect only on the client side.
Execution Timing: useEffect runs after paint (async); useLayoutEffect runs before paint (sync)
Blocking Nature: useEffect is non-blocking; useLayoutEffect blocks the browser from painting until it completes
Use Cases: useEffect for most side effects (data fetching, subscriptions); useLayoutEffect for DOM measurements and preventing flicker
Performance Impact: useEffect is optimized for performance; useLayoutEffect can cause jank if overused
SSR Compatibility: useEffect works on server; useLayoutEffect does not
Equivalent Lifecycles: useLayoutEffect timing matches componentDidMount/componentDidUpdate; useEffect runs after paint
You need to read the width of a div right after it renders to set its height. Which hook would you choose and why?
If you put a console.log inside useEffect and another inside useLayoutEffect, when will each log appear relative to the paint?
What would happen if you tried to access offsetHeight inside a useEffect callback?
A modal component focuses an input on open using useEffect, but the focus sometimes flickers. How would you fix it?
After refactoring a component to useLayoutEffect for a DOM read, you see a warning about layout thrashing. Explain why and how you’d decide which hook to keep.
Switching a list item from useEffect to useLayoutEffect introduced a performance regression. Walk me through how you’d debug and resolve it.
Design a reusable tooltip that must measure its target element and position itself before paint. Which hook(s) would you use and how would you handle subsequent updates?
Many components in a large app use useLayoutEffect for measurements, causing main‑thread blocking. How would you mitigate this at scale?
In a data‑grid component, heavy calculations are currently in useLayoutEffect, leading to layout shift. Discuss the trade‑offs of moving them to useEffect.
Your team is migrating a legacy codebase that relies on componentDidMount/componentDidUpdate for DOM reads. How would you plan the migration to hooks, deciding where to use useLayoutEffect versus useEffect while considering bundle size and long‑term maintainability?
Across several squads, some use useEffect for layout reads, causing visual glitches. Propose an architecture guideline and enforcement strategy to standardize the use of useLayoutEffect where appropriate.
If you were to create a custom hook that abstracts the choice between useEffect and useLayoutEffect based on environment (client vs server), what considerations would you include to avoid breaking existing components?